﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Text;

public class RefPrint
{
    public static PrintLog PrintTool;

    private static StringBuilder sb = new StringBuilder();

    public static void PrintClassInfo<T>(T obj) where T : class
    {
        if (obj == null)
        {
            PrintTool.WriteLine("print class of null");
            return;
        }
        sb = new StringBuilder();
        sb.AppendLine(obj.GetType().Name);
        Type t = obj.GetType();
        PrintFields(t, obj);
        PrintTool.WriteLine(sb.ToString());
    }

    public static void PrintClassInfo(object obj)
    {
        if (obj == null)
        {
            PrintTool.WriteLine("print class of null");
            return;
        }

        sb = new StringBuilder();
        sb.AppendLine(obj.GetType().Name);
        Type t = obj.GetType();
        PrintFields(t, obj);
        PrintTool.WriteLine(sb.ToString());
    }

    public static void PrintClassInfo(object obj, string path)
    {
        if (obj == null)
        {
            PrintTool.WriteLine("print class of null");
            return;
        }

        sb = new StringBuilder();
        string[] strList = path.Split('.');

        Type t = obj.GetType();
        FieldInfo f = null;

        for (int i = 0; i < strList.Length; i++)
        {
            f = GetField(t, strList[i]);


            if (i == strList.Length - 1)
            {
                if (f != null)
                {
                    sb.AppendLine(f.GetValue(obj).ToString());
                }
                return;
            }

            t = f.GetType();
        }



        PrintTool.WriteLine(sb.ToString());
    }

    public static FieldInfo GetField(Type type, string findField)
    {
        var fList = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

        foreach (var item in fList)
        {
            if (item.FieldType.Name.Equals(findField))
            {
                return item;
            }
        }
        return null;
    }






    public static void PrintList(object listValue)
    {
        IEnumerable e = listValue as IEnumerable;
        FieldInfo[] fList = null;
        int count = 0;
        foreach (var c in e)
        {
            fList = c.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public);
            foreach (var item in fList)
            {
                sb.AppendLine(item.FieldType.Name + "\t" + item.Name + "\t" + item.GetValue(c).ToString());
            }
            count++;
        }
        sb.AppendLine("个数:" + count);
    }

    public static void PrintAry(object aryValue)
    {
        IEnumerable e = aryValue as IEnumerable;
        FieldInfo[] fList = null;
        int count = 0;
        foreach (var c in e)
        {
            if (c.GetType().Name.Contains("String"))
            {
                sb.AppendLine(c.GetType().Name + "\t" + c);
            }
            else if (!c.GetType().Name.Contains("String") && c.GetType().IsClass)
            {
                fList = c.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public);
                foreach (var item in fList)
                {
                    sb.AppendLine(item.FieldType.Name + "\t" + item.Name + "\t" + item.GetValue(c));
                }
            }
            else
            {
                sb.AppendLine(c.GetType().Name + "\t" + c + "\t");
            }
            count++;
        }
        sb.AppendLine("个数:" + count);
    }

    public static void PrintDictionary(object dirValue)
    {
        IDictionary e = dirValue as IDictionary;
        FieldInfo[] fList = null;
        int count = 0;
        foreach (var c in e.Values)
        {
            fList = c.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public);
            foreach (var item in fList)
            {
                sb.AppendLine(item.FieldType.Name + "\t" + item.Name + "\t" + item.GetValue(c).ToString());
            }
            count++;
        }
        sb.AppendLine("个数:" + count);
    }

    public static void PrintMemebers(Type t, object value)
    {
        var mList = t.GetMembers();

        foreach (var item in mList)
        {
            sb.AppendLine("method: " + item.Name);
        }
    }

    public static void PrintFields(Type t, object value)
    {
        var fList = t.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        foreach (var item in fList)
        {
            if (!item.FieldType.IsClass || (item.FieldType.Name == "String"))
            {
                sb.AppendLine(item.FieldType.Name + "\t" + item.Name + "\t" + item.GetValue(value));
                continue;
            }

            if (item.FieldType.Name.Contains("List"))
            {
                sb.AppendLine("集合" + item.Name + ":");
                Object listValue = item.GetValue(value);
                PrintList(listValue);
                continue;
            }

            if (item.FieldType.Name.Contains("[]"))
            {
                sb.AppendLine("数组" + item.Name + ":");
                Object aryValue = item.GetValue(value);
                PrintAry(aryValue);
                continue;
            }

            if (item.FieldType.Name.Contains("Dictionary"))
            {
                sb.AppendLine("字典" + item.Name + ":");
                Object aryValue = item.GetValue(value);



                PrintDictionary(aryValue);
                continue;
            }

        }
    }

    public static void PrintProperties(Type t, object value)
    {
        var pList = t.GetProperties();

        foreach (var item in pList)
        {
            sb.AppendLine(item.Name + " " + item.GetValue(value, new object[] { }));
        }
    }
}

public interface PrintLog
{
    void WriteLine(string text);
}

public static class RefStatic
{

    public static FieldInfo RefField(this object t, string name, bool searchUp = false)
    {
        FieldInfo info = SearchField(t, name, searchUp);
        return info;
    }

    public static Object RefGetFieldVal(this object t, string name, bool searchUp = false)
    {
        FieldInfo info = SearchField(t, name, searchUp);
        return info.GetValue(t);
    }

    public static FieldInfo RefSetFieldVal(this object t, string name, object val, bool searchUp = false)
    {
        FieldInfo info = SearchField(t, name, searchUp);
        if (info != null)
            info.SetValue(t, val);

        return info;
    }

    public static FieldInfo RefStaticField(this object t, string name, bool searchUp = false)
    {
        FieldInfo info = t.GetType().GetField(name, BindingFlags.Static | BindingFlags.NonPublic);
        return info;
    }

    public static FieldInfo RefSetStaticFieldVal(this object t, string name, object val, bool searchUp = false)
    {
        FieldInfo info = t.GetType().GetField(name, BindingFlags.Static | BindingFlags.NonPublic);
        if (info != null)
            info.SetValue(t, val);

        return info;
    }


    public static PropertyInfo RefSetPropertyVal(this object t, string name, object val)
    {
        PropertyInfo info = t.GetType().GetProperty(name);
        if (info != null)
            info.SetValue(t, val, null);

        return info;
    }

    public static object RefExecuteMethod(this object t, string name, object[] parameters = null)
    {
        MethodInfo info = t.GetType().GetMethod(name, BindingFlags.NonPublic | BindingFlags.Instance);
        if (info != null)
            return info.Invoke(t, parameters);
        return null;
    }

    private static FieldInfo SearchField(object t, string name, bool parentSearch)
    {
        FieldInfo info = null;
        if (parentSearch)
        {
            Type type = t.GetType();
            while (info == null && type != null)
            {
                info = type.GetField(name, BindingFlags.Instance | BindingFlags.NonPublic);
                type = type.BaseType;
            }
        }
        else
            info = t.GetType().GetField(name, BindingFlags.Instance | BindingFlags.NonPublic);

        return info;
    }

}